home *** CD-ROM | disk | FTP | other *** search
- unit DMSQLUtils;
-
- interface
-
- const
- NullValueStr = '<null>';
-
- const
- // SQL statement portions
- sqlSelect = 'select';
- sqlWhere = 'where';
- sqlFrom = 'from';
- sqlGroup = 'group';
- sqlOrder = 'order';
- sqlBy = 'by';
- sqlGroupBy = sqlGroup + ' ' + sqlBy;
- sqlOrderBy = sqlOrder + ' ' + sqlBy;
- sqlHaving = 'having';
- sqlPlan = 'plan';
- sqlUnion = 'union';
-
- sqlValidTrailingChars = ' '#$D#$A;
-
- // This function extracts the select portion of the spedified SQL string.
- // Valid separators are spaces or $D$A (as in TQuery.SQL.Text). The select
- // keyword is not part of the result string.
- function ExtractSelectClause(SQL: string): string;
-
- // This function extracts the from portion of the spedified SQL string.
- // Valid separators are spaces or $D$A (as in TQuery.SQL.Text). The from
- // keyword is not part of the result string.
- function ExtractFromClause(SQL: string): string;
-
- // This function extracts the where portion of the spedified SQL string.
- // Valid separators are spaces or $D$A (as in TQuery.SQL.Text). The where
- // keyword is not part of the result string.
- function ExtractWhereClause(SQL: string): string;
-
- // This function extracts the having portion of the spedified SQL string.
- // Valid separators are spaces or $D$A (as in TQuery.SQL.Text). The having
- // keyword is not part of the result string.
- function ExtractHavingClause(SQL: string): string;
-
- // This function extracts the order by portion of the spedified SQL string.
- // Valid separators are spaces or $D$A (as in TQuery.SQL.Text). The order by
- // keywords are not part of the result string.
- function ExtractOrderByClause(SQL: string): string;
-
- // This function extracts the group by portion of the spedified SQL string.
- // Valid separators are spaces or $D$A (as in TQuery.SQL.Text). The group by
- // keywords are not part of the result string.
- function ExtractGroupByClause(SQL: string): string;
-
- // This function extracts the plan portion of the spedified SQL string.
- // Valid separators are spaces or $D$A (as in TQuery.SQL.Text). The plan
- // keyword is not part of the result string.
- function ExtractPlanClause(SQL: string): string;
-
- // Wrapper around System.Insert; inserts Src at position Index of
- // Dest, and returns the resulting string.
- function MergeStr(Src, Dest: string; Index: Integer): string;
-
- // A case insensitive Pos function.
- function InsensitivePos(Substr, Str: string): Integer;
-
- // Converts a TDateTime to a string which is valid for a SQL parser
- // (tested with InterBase).
- function FormatSQLDateTime(ADateTime: TDateTime): string;
-
- // Converts a string to a Variant, taking care of the special cases Null
- // and Unassigned.
- function SQLStringToVariant(SQL: string): Variant;
-
- implementation
-
- uses
- SysUtils;
-
- // internal routines
-
- // The PosEnh function works like Pos, except for the fact that it returns 0
- // is Substr is not part of Str (nothing new so far) *and* delimited by
- // characters included in LeadTrailChars or (if LeadNothing is True) nothing,
- // that is the end or the beginning of the string.
- // In addition, this function is case insensitive.
- // Example:
- // i := PosEnh('WHERE', Query1.SQL.Text, ' '$D$A, False);
- // In this case, i will be <> 0 only if the SQL statement contains the WHERE
- // keyword at the beginning or end of a line and delimited on the other side
- // by a space character. A WHERE keyword alone on a line would do as well.
- function PosEnh(Substr, Str, LeadTrailChars: string; LeadTrailNothing: Boolean): Integer;
- var
- LeadingChar, TrailingChar: Char;
- MyKeyword: string;
- Found: Boolean;
- begin
- Found := False;
- Result := InsensitivePos(Substr, Str);
- if Result <> 0 then begin
- MyKeyword := Copy(Str, Result, Length(Str));
-
- if not Found then begin
- // If the substring is a the beginning or end of the string,
- // optionally exit.
- if LeadTrailNothing and ((Result = 1) or (Length(MyKeyword) = Length(Substr))) then
- Found := True;
- end;
-
- if not Found then begin
- // If the substring is delimited by characters included in LeadTrailChars
- // we have found it.
- if (LeadTrailChars <> '') then begin
- LeadingChar := Copy(Str, Result - 1, 1)[1];
- TrailingChar := MyKeyword[Length(Substr) + 1];
- if (Pos(LeadingChar, LeadTrailChars) <> 0)
- and (Pos(TrailingChar, LeadTrailChars) <> 0) then
- Found := True;
- end;
- end;
-
- if not Found then
- // Recurse passing only the part of the string after the Result index.
- Result := PosEnh(Substr, Copy(Str, Result + Length(Substr),
- Length(Str)), LeadTrailChars, LeadTrailNothing);
-
- if not Found and (Result >= Length(Str)) then
- // If the end of the string is reached,
- // we haven't found what we were searching for.
- Result := 0;
- end;
- end;
-
- // Calls PosEnh for each string in Substrs, returning a value <> 0 the first
- // time that PosEnh does so.
- function MultiPosEnh(Substrs: array of string; Str, TrailingChars: string; TrailingNothing: Boolean): Integer;
- var
- g: Integer;
- begin
- Result := 0;
- for g := Low(Substrs) to High(Substrs) do begin
- Result := PosEnh(Substrs[g], Str, TrailingChars, TrailingNothing);
- if Result <> 0 then
- Break;
- end;
- end;
-
- // Implements the Extract*Clause functions.
- function ExtractSQLClause(SQL, Clause: string; OtherClauses: array of string): string;
- var
- AfterFoundClause: string;
- FoundClausePos, OtherClausesPos: Integer;
- begin
- Result := '';
- FoundClausePos := PosEnh(Clause, SQL, sqlValidTrailingChars, True);
- if FoundClausePos > 0 then begin
- AfterFoundClause := Copy(SQL, FoundClausePos + Length(Clause), Length(SQL) - FoundClausePos);
- OtherClausesPos := MultiPosEnh(OtherClauses, AfterFoundClause, sqlValidTrailingChars, True);
- if OtherClausesPos > 0 then
- Result := Trim(Copy(AfterFoundClause, 1, OtherClausesPos - 1))
- else
- Result := Trim(AfterFoundClause);
- end;
- end;
-
- // public routines
-
- function ExtractSelectClause(SQL: string): string;
- begin
- Result := ExtractSQLClause(SQL, sqlSelect, [sqlFrom]);
- end;
-
- function ExtractFromClause(SQL: string): string;
- begin
- Result := ExtractSQLClause(SQL, sqlFrom, [sqlWhere, sqlGroup, sqlHaving, sqlUnion, sqlPlan, sqlOrder]);
- end;
-
- function ExtractWhereClause(SQL: string): string;
- begin
- Result := ExtractSQLClause(SQL, sqlWhere, [sqlGroup, sqlHaving, sqlUnion, sqlPlan, sqlOrder]);
- end;
-
- function ExtractHavingClause(SQL: string): string;
- begin
- Result := ExtractSQLClause(SQL, sqlHaving, [sqlUnion, sqlPlan, sqlOrder]);
- end;
-
- function ExtractOrderByClause(SQL: string): string;
- begin
- Result := ExtractSQLClause(SQL, sqlOrder, ['']);
- if Result <> '' then
- Result := ExtractSQLClause(Result, sqlBy, ['']);
- end;
-
- function ExtractGroupByClause(SQL: string): string;
- begin
- Result := ExtractSQLClause(SQL, sqlGroup, ['']);
- if Result <> '' then
- Result := ExtractSQLClause(Result, sqlBy, [sqlHaving, sqlUnion, sqlPlan, sqlOrder]);
- end;
-
- function ExtractPlanClause(SQL: string): string;
- begin
- Result := ExtractSQLClause(SQL, sqlPlan, ['']);
- end;
-
- function MergeStr(Src, Dest: string; Index: Integer): string;
- var
- LocalDest: string;
- begin
- LocalDest := Dest;
- Insert(Src, LocalDest, Index);
- Result := LocalDest;
- end;
-
- function InsensitivePos(Substr, Str: string): Integer;
- begin
- Result := Pos(AnsiLowerCase(Substr), AnsiLowerCase(Str));
- end;
-
- function FormatSQLDateTime(ADateTime: TDateTime): string;
- var
- Year, Month, Day: Word;
- const
- MonthNames: array[1..12] of string =
- ('jan', 'feb', 'mar', 'apr', 'may', 'jun',
- 'jul', 'aug', 'sep', 'oct', 'nov', 'dec');
- begin
- DecodeDate(ADateTime, Year, Month, Day);
- Result := IntToStr(Day) + '-' + MonthNames[Month] + '-' + IntToStr(Year);
- // If there is a time portion, include it in the final string.
- if Frac(ADateTime) <> 0 then
- Result := Result + ' ' + FormatDateTime('hh"."nn"."ss', ADateTime);
- end;
-
- function SQLStringToVariant(SQL: string): Variant;
- begin
- if SQL = NullValueStr then
- Result := Null
- else if SQL = '' then
- Result := Unassigned
- else
- Result := SQL;
- end;
-
- end.
-